﻿using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using System.Text;

namespace EasySocket
{
    internal static class SocketKeeper
    {
        /// <summary>
        /// 从底层维持socket连接，
        /// 主要用于tcp
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="keepAliveTime"></param>
        /// <param name="timeOut"></param>
        public static void KeepAlive(this Socket socket, int keepAliveTime = 180 * 1000, int timeOut = 5 * 1000)
        {
            uint dummy = 0;
            byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3];
            BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0);//是否启用Keep-Alive
            BitConverter.GetBytes((uint)keepAliveTime).CopyTo(inOptionValues, Marshal.SizeOf(dummy));//多长时间开始第一次探测
            BitConverter.GetBytes((uint)timeOut).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);//探测时间间隔

            try
            {
                socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
            }
            catch (PlatformNotSupportedException)
            {
                try
                {
                    socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                }
                catch (PlatformNotSupportedException)
                {

                }
            }

        }

        public static void ResolveSocketDll()
        {
            AssemblyLoadContext.Default.Resolving += AssemblyResolving;
        }

        private static Assembly AssemblyResolving(AssemblyLoadContext context, AssemblyName assemblyName)
        {
            var current = Assembly.GetExecutingAssembly();
            var embedPath = $"EasySocket.Lib.{assemblyName.Name}.dll";
            try
            {
                using(var stream = current.GetManifestResourceStream(embedPath))
                {
                    return context.LoadFromStream(stream);
                }
            }
            catch { }

            return null;
        }
    }
}
